﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using NHibernate;

namespace Core
{
  public static class Extensions
  {
    ///<summary>Get all exception messages, separated by ;</summary>
    ///<param name="input"></param>
    ///<returns></returns>
    public static string AllMessages(this Exception input)
    {
      return input.AllMessages("; ");
    }

    ///<summary>Get all exception messages</summary>
    ///<param name="input"></param>
    ///<param name="seperator"></param>
    ///<returns></returns>
    public static string AllMessages(this Exception input, string seperator)
    {
      if (input == null)
      {
        return string.Empty;
      }

      var sb = new StringBuilder();
      while (input != null)
      {
        if (sb.Length != 0)
        {
          sb.Append(seperator);
        }
        sb.Append(input.Message);
        input = input.InnerException;
      }
      return sb.ToString();
    }

    /// <summary>Returns a string with all the items concatenated together, joined with ; </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static string Joined(this List<string> input)
    {
      return input.Joined("; ");
    }

    /// <summary>Returns a string with all the items concatenated together.</summary>
    ///<param name="input"></param>
    ///<param name="seperator"></param>
    ///<returns></returns>
    public static string Joined(this List<string> input, string seperator)
    {
      if (input == null || input.Count == 0)
      {
        return string.Empty;
      }

      return String.Join(seperator, input.ToArray());
    }

    ///<summary>Return the input string. However, if it is null or empty, return the default value</summary>
    ///<param name="input"></param>
    ///<param name="defaultValue"></param>
    ///<returns></returns>
    public static string DefaultingTo(this string input, string defaultValue)
    {
      return input.HasContent() ? input : defaultValue;
    }

    ///<summary>Determine if this string is empty (is null or empty)</summary>
    public static bool HasNoContent(this string input)
    {
      return string.IsNullOrEmpty(input);
    }

    ///<summary>Determine if this string has content (is not null or empty)</summary>
    ///<param name="input"></param>
    ///<returns></returns>
    public static bool HasContent(this string input)
    {
      return !string.IsNullOrEmpty(input);
    }

    public static int AsInt(this object input)
    {
      if (input != null)
      {
        int result;
        if (Int32.TryParse(input.ToString(), out result))
        {
          return result;
        }
      }
      return 0;
    }

    ///<summary>Determine an age today</summary>
    ///<param name="earlierDate"></param>
    ///<returns></returns>
    public static int AgeToday(this DateTime earlierDate)
    {
      return AgeAt(earlierDate, DateTime.Today);
    }

    ///<summary>Determine an age at a date</summary>
    ///<param name="earlier"></param>
    ///<param name="later"></param>
    ///<returns></returns>
    public static int AgeAt(this DateTime earlier, DateTime later)
    {
      if(later <= earlier)
      {
        return 0;
      }

      var age = later.Year - earlier.Year;

      if (later.Month < earlier.Month)
      {
        return age - 1;
      }
      
      if (later.Month == earlier.Month)
      {
        if (later.Day < earlier.Day)
        {
          return age - 1;
        }
      }

      return age;
    }

    ///<summary></summary>
    ///<param name="entity"></param>
    ///<typeparam name="T"></typeparam>
    public static void CreateIndependentInstances<T>(this T entity)
    {
      var assembly = Assembly.GetExecutingAssembly();

      foreach (var fieldInfo in typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
      {
        fieldInfo.SetValue(entity, assembly.CreateInstance(fieldInfo.FieldType.FullName));
      }
    }


  }
}